import { createParser } from 'eventsource-parser';

import { apiDomain } from '@/config';
import { getRecoilOfUser } from '@/store/user';


export async function* streamAsyncIterable(stream: ReadableStream) {
  const reader = stream.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        return;
      }
      yield value;
    }
  } finally {
    reader.releaseLock();
  }
}

export const fetchOfSSE = (url: string, options: RequestInit & { onMessage: (message: string) => void }) => {
  return new Promise<void>(async (resolve, reject) => {
    const { onMessage, ...fetchOptions } = options;
    let requestUrl = url;
    if (url?.indexOf('http') !== 0) {
      requestUrl = apiDomain + url;
    }

    const user = getRecoilOfUser();

    const token = user.token;
    if (token) {
      (options.headers as any)['Authorization'] = 'Bearer ' + token;
    }
    const resp = await fetch(requestUrl, fetchOptions);
    if (!resp.ok) {
      const error = await resp.json().catch(() => null);
      throw new Error(!error ? JSON.stringify(error) : `${resp.status} ${resp.statusText}`);
    }
    const parser = createParser((event) => {
      if (event.type === 'event') {
        onMessage(event.data);
      }
      resolve();
    });
    for await (const chunk of streamAsyncIterable(resp.body!)) {
      const str = new TextDecoder().decode(chunk);
      try {
        const obj = JSON.parse(str);
        if (obj.code === 500) {
          reject(new Error(obj.msg));
        }
      } catch (err) {}
      parser.feed(str);
    }
  });
};
